{
 "cells": [
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "# Plotting polygons with Folium\n",
    "This example demonstrates how to plot polygons on a Folium map."
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "import geopandas as gpd\n",
    "import geodatasets\n",
    "import folium\n",
    "import matplotlib.pyplot as plt"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "## Load geometries\n",
    "This example uses the nybb dataset, which contains polygons of New York boroughs."
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "path = geodatasets.get_path(\"nybb\")\n",
    "df = gpd.read_file(path)\n",
    "df.head()"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "Plot from the original dataset"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {
    "tags": [
     "nbsphinx-thumbnail"
    ]
   },
   "outputs": [],
   "source": [
    "df.plot(figsize=(6, 6))\n",
    "plt.show()"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "Notice that the values of the polygon geometries do not directly represent the values of latitude or longitude in a geographic coordinate system.\n",
    "To view the coordinate reference system of the geometry column, access the `crs` attribute:"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "df.crs"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "The [EPSG:2263](https://spatialreference.org/ref/epsg/2263/) crs is a projected coordinate reference system with linear units (ft in this case).\n",
    "As folium (i.e. leaflet.js) by default accepts values of latitude and longitude (angular units) as input, we need to project the geometry to a geographic coordinate system first."
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "# Use WGS 84 (epsg:4326) as the geographic coordinate system\n",
    "df = df.to_crs(epsg=4326)\n",
    "print(df.crs)\n",
    "df.head()"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "df.plot(figsize=(6, 6))\n",
    "plt.show()"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "## Create Folium map"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "m = folium.Map(location=[40.70, -73.94], zoom_start=10, tiles=\"CartoDB positron\")\n",
    "m"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "### Add polygons to map\n",
    "Overlay the boundaries of boroughs on map with borough name as popup:"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "for _, r in df.iterrows():\n",
    "    # Without simplifying the representation of each borough,\n",
    "    # the map might not be displayed\n",
    "    sim_geo = gpd.GeoSeries(r[\"geometry\"]).simplify(tolerance=0.001)\n",
    "    geo_j = sim_geo.to_json()\n",
    "    geo_j = folium.GeoJson(data=geo_j, style_function=lambda x: {\"fillColor\": \"orange\"})\n",
    "    folium.Popup(r[\"BoroName\"]).add_to(geo_j)\n",
    "    geo_j.add_to(m)\n",
    "m"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "### Add centroid markers\n",
    "In order to properly compute geometric properties, in this case centroids, of the geometries, we need to project the data to a projected coordinate system."
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "# Project to NAD83 projected crs\n",
    "df = df.to_crs(epsg=2263)\n",
    "\n",
    "# Access the centroid attribute of each polygon\n",
    "df[\"centroid\"] = df.centroid"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "Since we're again adding a new geometry to the Folium map, we need to project the geometry back to a geographic coordinate system with latitude and longitude values."
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "# Project to WGS84 geographic crs\n",
    "\n",
    "# geometry (active) column\n",
    "df = df.to_crs(epsg=4326)\n",
    "\n",
    "# Centroid column\n",
    "df[\"centroid\"] = df[\"centroid\"].to_crs(epsg=4326)\n",
    "\n",
    "df.head()"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "for _, r in df.iterrows():\n",
    "    lat = r[\"centroid\"].y\n",
    "    lon = r[\"centroid\"].x\n",
    "    folium.Marker(\n",
    "        location=[lat, lon],\n",
    "        popup=\"length: {} <br> area: {}\".format(r[\"Shape_Leng\"], r[\"Shape_Area\"]),\n",
    "    ).add_to(m)\n",
    "\n",
    "m"
   ]
  }
 ],
 "metadata": {
  "kernelspec": {
   "display_name": "Python 3",
   "language": "python",
   "name": "python3"
  },
  "language_info": {
   "codemirror_mode": {
    "name": "ipython",
    "version": 3
   },
   "file_extension": ".py",
   "mimetype": "text/x-python",
   "name": "python",
   "nbconvert_exporter": "python",
   "pygments_lexer": "ipython3",
   "version": "3.9.1"
  }
 },
 "nbformat": 4,
 "nbformat_minor": 4
}
